interface JsonElement {
    type: 'element' | 'text',
    name: string,
    text?: string,
    children?: JsonElement[],
    attributes: { [k: string]: string },
}

export interface MdcTable {
    tableType: string,
    title: string,
    content: string,
    desc?: string,
}

export function isMdcTable(mdc: any): mdc is MdcTable {
    // @ts-ignore
    return !!mdc.tableType
}

/**
 * Table属性类型
 * @author  韦胜健
 * @date    2020/9/18 9:37
 */
interface TableAttr {
    name: string,
    title: string,
}

/**
 * Table类型
 * @author  韦胜健
 * @date    2020/9/18 9:37
 */
interface TableType {
    name: string,               // 表格的
    attrs: TableAttr[],         // 表格属性
}

/*已经定义的table类型*/
const types = [] as TableType[]

/**
 * 注册table类型
 * @author  韦胜健
 * @date    2020/9/18 9:38
 */
export function registryTableType(name: string, attrs: TableAttr[]) {
    types.push({
        name,
        attrs,
    })
}

registryTableType('props', [
    {name: 'name', title: '属性名'},
    {name: 'type', title: '类型'},
    {name: 'default', title: '默认值'},
    {name: 'desc', title: '说明'},
])

registryTableType('slots', [
    {name: 'name', title: '插槽名称'},
    {name: 'desc', title: '说明'},
])

registryTableType('methods', [
    {name: 'name', title: '方法名'},
    {name: 'params', title: '参数说明'},
    {name: 'desc', title: '说明'},
])

registryTableType('scoped-slots', [
    {name: 'name', title: '作用域插槽名'},
    {name: 'params', title: '参数说明'},
    {name: 'desc', title: '说明'},
])

registryTableType('events', [
    {name: 'name', title: '事件名'},
    {name: 'params', title: '参数'},
    {name: 'desc', title: '说明'},
])

/**
 * 将对象转化为xml字符串
 * @author  韦胜健
 * @date    2020/9/18 9:36
 */
function toXmlString(obj: any, removeRootTag = false) {
    if (obj.type === 'text') {
        return obj.text.trim() == '' ? '' : obj.text
    }
    return `${!removeRootTag ? `<${obj.name}>` : ''}${!!obj.children && obj.children.length > 0 ? obj.children.map((child: any) => toXmlString(child)).join('') : obj.text}${!removeRootTag ? `</${obj.name}>` : ''}`
}

/**
 * 根据props数组信息转化为markdown 表格字符串
 * @author  韦胜健
 * @date    2020/9/18 9:36
 */
function buildPropsMarkdownTable(tableType: string, propsList: { [k: string]: string }[]): string {
    for (let i = 0; i < types.length; i++) {
        const type = types[i];
        if (type.name === tableType) {
            const {attrs} = type

            return `|${attrs.map(attr => attr.title).join('|')}|\n|${attrs.map(() => ':--')
                .join('|')}|\n` + propsList.map(props => {
                return `|${attrs.map(attr => props[attr.name] || '').join('|')}|`
            }).join('\n')
        }
    }

    console.error('无法识别tableType:' + tableType)

    return ''
}

export function processTableString(tableString: string) {
    try {
        const parseXml = (window as any).parseXml
        const jsonData = parseXml(tableString) as JsonElement
        const root = jsonData.children![0]
        let tableDesc: string | undefined = undefined;

        // title 表格标题
        const {attributes: {title}, name: tableType} = root

        const propsList = root.children!.reduce((ret: { [k: string]: string }[], child: JsonElement) => {
            // 忽略setting节点下的文本节点
            if (child.type === "element") {
                if (child.name === 'desc') {
                    if (!!child.children && child.children.length > 0) {
                        tableDesc = child.children[0].text as string
                    }
                } else {
                    const item = {...(child.attributes || {})}
                    child.children!.forEach(subChild => {
                        if (subChild.type === "element") {
                            // console.log(subChild)
                            item[subChild.name] = toXmlString(subChild, true).replace(/\n/g, '')
                        }
                    })
                    if (!!item.type && item.type.indexOf('TYPE ') === 0) {
                        item.type = `<a href="${item.type}">${item.type}</a>`
                    }
                    ret.push(item)
                }
            }
            return ret
        }, [])

        return {
            tableType,
            desc: tableDesc,
            title,
            content: buildPropsMarkdownTable(tableType, propsList),
        } as MdcTable
    } catch (e) {
        console.error('解析失败！')
        console.log(tableString)
        throw e
    }
}

export const MATCH_TABLE_STRING = /```angular2html((?:.|\r|\n|\t)*?)```/g